package 作用域相关;


import 抽象语法树节点.变量定义;
import 抽象语法树节点.抽象语法树;
import 抽象语法树节点.表达式列表;

import java.util.ArrayList;
import java.util.List;

public class 符号表 {

    public final 全局作用域 全局作用域 = new 全局作用域();

    public 符号表() {
        初始化类型系统();
    }

    protected void 初始化类型系统() {
        全局作用域.定义((符号) 类型索引.逻辑型.类型);
        全局作用域.定义((符号) 类型索引.字符型.类型);
        全局作用域.定义((符号) 类型索引.整数型.类型);
        全局作用域.定义((符号) 类型索引.浮点型.类型);
        全局作用域.定义((符号) 类型索引.空.类型);
    }


    private static final 类型 逻辑型 = 类型索引.逻辑型.类型;
    private static final 类型 字符型 = 类型索引.字符型.类型;
    private static final 类型 整数型 = 类型索引.整数型.类型;
    private static final 类型 浮点型 = 类型索引.浮点型.类型;
    private static final 类型 空 = 类型索引.空.类型;

    //region 类型运算与类型提升

    // @formatter:off
    public static final 类型[][] 二元运算结果类型 = new 类型[][]{ // 返回 空 表示不支持该运算
            //          结构体   逻辑型  字符型   整数型   浮点型   空
            /*结构体*/ {空,       空,    空,       空,     空,     空},
            /*逻辑型*/ {空,       空,    空,       空,     空,     空},
            /*字符型*/ {空,       空,    字符型,   整数型,  浮点型,  空},
            /*整数型*/ {空,       空,    整数型,   整数型,  浮点型,  空},
            /*浮点型*/ {空,       空,    浮点型,   浮点型,  浮点型,  空},
            /*空*/     {空,       空,    空,       空,     空,     空},
    };
    // @formatter:on


    // @formatter:off
    public static final 类型[][] 关系运算结果类型 = new 类型[][]{ // 返回 空 表示不支持该运算
            //          结构体   逻辑型  字符型   整数型   浮点型   空
            /*结构体*/ {空,       空,    空,       空,     空,     空},
            /*逻辑型*/ {空,       空,    空,       空,     空,     空},
            /*字符型*/ {空,       空,    逻辑型,   逻辑型,  逻辑型,  空},
            /*整数型*/ {空,       空,    逻辑型,   逻辑型,  逻辑型,  空},
            /*浮点型*/ {空,       空,    逻辑型,   逻辑型,  逻辑型,  空},
            /*空*/     {空,       空,    空,       空,     空,     空},
    };
    // @formatter:on


    // @formatter:off
    public static final 类型[][] 匹值运算结果类型 = new 类型[][]{ // 返回 空 表示不支持该运算
            //          结构体   逻辑型  字符型   整数型   浮点型   空
            /*结构体*/ {空,       空,    空,       空,     空,     空},
            /*逻辑型*/ {空,       逻辑型, 空,       空,     空,     空},
            /*字符型*/ {空,       空,    逻辑型,   逻辑型,  逻辑型,  空},
            /*整数型*/ {空,       空,    逻辑型,   逻辑型,  逻辑型,  空},
            /*浮点型*/ {空,       空,    逻辑型,   逻辑型,  逻辑型,  空},
            /*空*/     {空,       空,    空,       空,     空,     空},
    };
    // @formatter:on


    // @formatter:off
    public static final 类型[][] 类型提升表 = new 类型[][]{ // 返回 null 表示不支持类型提升
            //          结构体   逻辑型   字符型   整数型   浮点型   空
            /*结构体*/ {null,     null,   null,   null,    null,  null},
            /*逻辑型*/ {null,     null,   null,   null,    null,  null},
            /*字符型*/ {null,     null,   null,  整数型,   浮点型,  null},
            /*整数型*/ {null,     null,   null,   null,   浮点型,  null},
            /*浮点型*/ {null,     null,   null,   null,    null,  null},
            /*空*/     {null,     null,   null,   null,    null,  null},
    };
    // @formatter:on

    //endregion


    public String toString() {
        return 全局作用域.toString();
    }


    // bop (binary operator)
    public 类型 二元运算(抽象语法树 左, 抽象语法树 右) {
        return 取结果类型(二元运算结果类型, 左, 右);
    }

    // relop (relational operator)
    public 类型 关系运算(抽象语法树 左, 抽象语法树 右) {
        return 取结果类型(关系运算结果类型, 左, 右);
    }

    // eqop (equality operator)
    public 类型 匹值运算(抽象语法树 左, 抽象语法树 右) {
        return 取结果类型(匹值运算结果类型, 左, 右);
    }

    // uminus
    public 类型 取负(抽象语法树 树) {
        return 树.求值类型;
    }

    // unot
    public 类型 取反(抽象语法树 树) {
        return 类型索引.逻辑型.类型;
    }

    public 类型 数组访问(抽象语法树 数组, 抽象语法树 下标) {
        var 符号 = (变量符号) 数组.作用域.解析(数组.token.getText());
        数组.符号 = 符号;
        下标.类型提升 = 类型提升表[数组.求值类型.取类型索引()][整数型.取类型索引()];
        return ((数组类型) 符号.类型).元素类型;
    }

    public 类型 方法调用(抽象语法树 方法, 表达式列表 参数) {
        var 符号 = (方法符号) 方法.作用域.解析(方法.token.getText());
        方法.符号 = 符号;
        
        // 给方法里每个参数都计算类型提升
        if (参数 != null) {
            // 由于使用的是LinkedHashMap， 所以这里可以把参数按顺序取出来
            var 类型列表 = new ArrayList<类型>();
            for (var 变量名 : 符号.取成员().keySet()) {
                var 变量 = (变量符号) 符号.取成员().get(变量名);
                类型列表.add(变量.类型);
            }
            
            for (var i = 0; i < 参数.表达式.size(); i++) {
                var 参数节点 = 参数.表达式.get(i);
                var 当前类型 = 参数节点.求值类型;
                var 目标类型 = 类型列表.get(i);
                参数节点.类型提升 = 类型提升表[当前类型.取类型索引()][目标类型.取类型索引()];
            }
        }
        
        return 符号.类型;
    }

    public 类型 成员访问(抽象语法树 对象, String 成员名) {
        var 作用域 = (结构体符号) 对象.求值类型;
        var 符号 = 作用域.解析成员(成员名);
        return 符号.类型;
    }

    
    public void 赋初值(变量定义 变量, 抽象语法树 初值) {
        初值.类型提升 = 类型提升表[初值.求值类型.取类型索引()][变量.求值类型.取类型索引()];        
    }

    public void 返回语句(方法符号 方法, 抽象语法树 返回值) {
        返回值.类型提升 = 类型提升表[返回值.求值类型.取类型索引()][方法.类型.取类型索引()];
    }
    
    public void 赋值语句(抽象语法树 变量, 抽象语法树 值) {
        值.类型提升 = 类型提升表[值.求值类型.取类型索引()][变量.求值类型.取类型索引()];
    }
    
    
    public 方法符号 取方法符号(作用域 作用域) {
        do {
            if (作用域 instanceof 方法符号) {
                return (方法符号) 作用域;
            }

            作用域 = 作用域.取外围作用域();
        }
        while (作用域 != null);
        return null;
    }
    
    
    private static 类型 取结果类型(类型[][] 类型表, 抽象语法树 左值, 抽象语法树 右值) {
        var 左值类型索引 = 左值.求值类型.取类型索引();
        var 右值类型索引 = 右值.求值类型.取类型索引();
        var 运算结果类型 = 类型表[左值类型索引][右值类型索引];
        
        // 自动类型提升
        左值.类型提升 = 类型提升表[左值类型索引][运算结果类型.取类型索引()];
        右值.类型提升 = 类型提升表[右值类型索引][运算结果类型.取类型索引()];
        return 运算结果类型;
    }
}
